<!DOCTYPE html>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<body></body>
<script>
function assertAnimationEffect({keyframes, expect}) {
  var target = document.createElement('target');
  document.body.appendChild(target);
  var animation = target.animate(keyframes, {duration: 1, fill: 'forwards'});
  animation.pause();
  for (var {at, is} of expect) {
    animation.currentTime = at;
    for (var property in is)
      assert_equals(getComputedStyle(target)[property], is[property], `${property} is ${is[property]} at ${at}`);
  }
  target.remove();
}

function createIterable(iterations) {
  return {
    [Symbol.iterator]() {
      var i = 0;
      return {next: () => iterations[i++]};
    },
  };
}

test(() => {
  assertAnimationEffect({
    keyframes: createIterable([
      {done: false, value: {left: '100px'}},
      {done: false, value: {left: '300px'}},
      {done: false, value: {left: '200px'}},
      {done: true},
    ]),
    expect: [
      {at: 0, is: {left: '100px'}},
      {at: 0.25, is: {left: '200px'}},
      {at: 0.5, is: {left: '300px'}},
      {at: 0.75, is: {left: '250px'}},
      {at: 1, is: {left: '200px'}},
    ],
  });
}, 'Custom iterator with basic keyframes.');

test(() => {
  assertAnimationEffect({
    keyframes: {
      left: createIterable([
        {done: false, value: '100px'},
        {done: false, value: '300px'},
        {done: false, value: '200px'},
        {done: true},
      ]),
    },
    expect: [
      {at: 0, is: {left: '100px'}},
      {at: 0.25, is: {left: '200px'}},
      {at: 0.5, is: {left: '300px'}},
      {at: 0.75, is: {left: '250px'}},
      {at: 1, is: {left: '200px'}},
    ],
  });
}, 'Custom iterator in property indexed keyframes.');

test(() => {
  var keyframes = createIterable([
    {done: false, value: {left: '100px'}},
    {done: false, value: {left: '300px'}},
    {done: false, value: {left: '200px'}},
    {done: true},
  ]);
  keyframes.easing = 'ease-in-out';
  keyframes.offset = '0.1';
  assertAnimationEffect({
    keyframes,
    expect: [
      {at: 0, is: {left: '100px'}},
      {at: 0.25, is: {left: '200px'}},
      {at: 0.5, is: {left: '300px'}},
      {at: 0.75, is: {left: '250px'}},
      {at: 1, is: {left: '200px'}},
    ],
  });
}, 'easing and offset are ignored on iterable objects.');

test(() => {
  assertAnimationEffect({
    keyframes: createIterable([
      {done: false, value: {left: '100px', top: '200px'}},
      {done: false, value: {left: '300px'}},
      {done: false, value: {left: '200px', top: '100px'}},
      {done: true},
    ]),
    expect: [
      {at: 0, is: {left: '100px', top: '200px'}},
      {at: 0.25, is: {left: '200px', top: '175px'}},
      {at: 0.5, is: {left: '300px', top: '150px'}},
      {at: 0.75, is: {left: '250px', top: '125px'}},
      {at: 1, is: {left: '200px', top: '100px'}},
    ],
  });
}, 'Custom iterator with multiple properties specified.');

test(() => {
  assertAnimationEffect({
    keyframes: createIterable([
      {done: false, value: {left: '100px'}},
      {done: false, value: {left: '250px', offset: 0.75}},
      {done: false, value: {left: '200px'}},
      {done: true},
    ]),
    expect: [
      {at: 0, is: {left: '100px'}},
      {at: 0.25, is: {left: '150px'}},
      {at: 0.5, is: {left: '200px'}},
      {at: 0.75, is: {left: '250px'}},
      {at: 1, is: {left: '200px'}},
    ],
  });
}, 'Custom iterator with offset specified.');

test(() => {
  assert_throws_js(TypeError, () => {
    assertAnimationEffect({
      keyframes: createIterable([
        {done: false, value: {left: '100px'}},
        {done: false, value: 1234},
        {done: false, value: {left: '200px'}},
        {done: true},
      ]),
      expect: [],
    });
  });
}, 'Custom iterator with non object keyframe should throw.');

test(() => {
  assert_throws_js(TypeError, () => {
    assertAnimationEffect({
      keyframes: {
        left: createIterable([
          {done: false, value: {toString: null}},
          {done: true},
        ]),
      },
      expect: [],
    });
  });
}, 'Custom iterator in property indexed keyframes with null toString method should throw.');
</script>
